/**
 * can_send.c - 发送递增数的CAN程序，支持动态修改CAN帧ID
 * 
 * 使用方法: ./can_send <can设备名> <初始can帧ID(十六进制)>
 * 例如: ./can_send can0 123
 * 
 * 运行时输入新的十六进制ID可以动态改变发送帧的ID
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/can.h>
#include <linux/can/raw.h>

// 全局变量，用于在线程间共享
volatile unsigned int current_can_id;
pthread_mutex_t can_id_mutex = PTHREAD_MUTEX_INITIALIZER;

// 用户输入处理线程
void* input_thread(void* arg) {
    char input[32];
    unsigned int new_id;

    printf("\n您可以输入新的CAN帧ID（十六进制格式）来动态改变发送帧的ID\n");
    printf("例如: 输入 '123' 将ID改为0x123\n");

    while (1) {
        printf("\n请输入新的CAN帧ID (十六进制): ");
        fflush(stdout);
        
        if (fgets(input, sizeof(input), stdin) != NULL) {
            // 移除换行符
            input[strcspn(input, "\n")] = 0;
            
            // 解析十六进制输入
            if (sscanf(input, "%x", &new_id) == 1) {
                pthread_mutex_lock(&can_id_mutex);
                current_can_id = new_id;
                pthread_mutex_unlock(&can_id_mutex);
                printf("CAN帧ID已更改为: 0x%X\n", new_id);
            } else {
                printf("无效的输入！请使用十六进制格式（例如: 123）\n");
            }
        }
    }
    return NULL;
}

int main(int argc, char *argv[]) {
    int s; 
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;
    int counter = 0;
    pthread_t tid;
    
    // 检查命令行参数
    if (argc != 3) {
        printf("使用方法: %s <can设备名> <初始can帧ID(十六进制)>\n", argv[0]);
        printf("例如: %s can0 123\n", argv[0]);
        return 1;
    }
    
    // 解析初始CAN帧ID参数（十六进制）
    if (sscanf(argv[2], "%x", &current_can_id) != 1) {
        printf("错误: CAN帧ID必须是有效的十六进制数\n");
        return 1;
    }
    
    
    // 创建用户输入线程
    if (pthread_create(&tid, NULL, input_thread, NULL) != 0) {
        perror("创建输入线程失败");
        close(s);
        return 1;
    }
    
    printf("开始发送递增数据到 %s，初始CAN帧ID: 0x%X\n", argv[1], current_can_id);
    
    // 循环发送递增数据
    while (1) {
	if (counter % 100 == 0) {
//		char cmd[128] = {};
//		sprintf(cmd, "ifconfig %s down", argv[1]);
//		system(cmd);
//		memset(cmd, 0, sizeof(cmd));

//		sprintf(cmd, "ip link set %s up type can bitrate 250000 sample-point 0.75", argv[1]);
//		system(cmd);
//		memset(cmd, 0, sizeof(cmd));


//		sprintf(cmd, "ip -details link show %s", argv[1]);
//		system(cmd);
//		memset(cmd, 0, sizeof(cmd));
	        // 创建socket
        	if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
	            perror("创建socket失败");
	            return 1;
        	}
    
	        // 指定CAN设备
        	strcpy(ifr.ifr_name, argv[1]);
	        if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
        	    perror("获取接口索引失败");
 		    close(s);
        	    return 1;
        	}
    
	        // 绑定socket到CAN接口
	        addr.can_family = AF_CAN;
	        addr.can_ifindex = ifr.ifr_ifindex;
	        if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
	            perror("绑定socket失败");
	            close(s);
	            return 1;
	       	}
	}

        counter++;
        // 设置CAN帧
        pthread_mutex_lock(&can_id_mutex);
        frame.can_id = current_can_id;
        pthread_mutex_unlock(&can_id_mutex);
        
        frame.can_dlc = 8;  // 数据长度为8字节
        
        // 将counter值放入CAN帧数据中
        frame.data[0] = (counter >> 56) & 0xFF;
        frame.data[1] = (counter >> 48) & 0xFF;
        frame.data[2] = (counter >> 40) & 0xFF;
        frame.data[3] = (counter >> 32) & 0xFF;
        frame.data[4] = (counter >> 24) & 0xFF;
        frame.data[5] = (counter >> 16) & 0xFF;
        frame.data[6] = (counter >> 8) & 0xFF;
        frame.data[7] = counter & 0xFF;
        
        // 发送CAN帧
        if (write(s, &frame, sizeof(struct can_frame)) != sizeof(struct can_frame)) {
            perror("发送CAN帧失败");
            close(s);
            return 1;
        }
        
        printf("\r已发送: %d (ID: 0x%X)", counter, frame.can_id);
        fflush(stdout);
        
        // 短暂延时
        usleep(100 * 1000);  // 100ms
	if (counter % 100 == 0) {
		printf("close can, counter = %d\n", counter);
        	close(s);
		sleep(1);
	}
    }
    
    // 清理资源
    pthread_cancel(tid);
    pthread_join(tid, NULL);
    return 0;
}
